﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using StockLib;

namespace StockControl
{
    public delegate void StockGridControlSortNeededHandler(object sender, EventArgs e);

    public partial class StockGridControl : DataGridView
    {
        const int frozeColumns = 3;

        /// <summary>
        /// 容器数据更改事件
        /// </summary>
        public event StockGridControlSortNeededHandler SortNeeded;

        private int currentRowOffset = 0;

        private int currentRowIndex = 0;

        private int firstRowIndex = 0;

        private int currentColumnOffset = 0;

        public DataGridViewColumn SortNeededColumn { get; set; }

        public SortOrder SortNeededOrder { get; set; }

        public StockGridControl()
        {
            InitializeComponent();

            this.Font = StockProfile.Fonts.GridFont;
            this.GridColor = StockProfile.Colors.GridLineColor;
            this.DefaultCellStyle.ForeColor = StockProfile.Colors.GridTextColor;
            this.ColumnHeadersDefaultCellStyle.BackColor = StockProfile.Colors.GridHeadBackColor;
            this.ColumnHeadersDefaultCellStyle.ForeColor = StockProfile.Colors.GridHeadTextColor;

            this.Columns["Nam"].DefaultCellStyle.ForeColor = StockProfile.Colors.GridHiTextColor;
            this.Columns["Code"].DefaultCellStyle.ForeColor = StockProfile.Colors.GridHiTextColor;

            this.AutoGenerateColumns = false;
            this.SortNeededColumn = this.Columns["Amplitude"];
            this.SortNeededOrder = SortOrder.Descending;
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            ScrollPage(e.Delta / 120);

            base.OnMouseWheel(e);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (SortNeededColumn != null)
            {
                SortNeededColumn.HeaderCell.SortGlyphDirection = SortNeededOrder;
            }

            base.OnPaint(e);
        }

        public new object DataSource
        {
            get
            {
                return base.DataSource;
            }
            set
            {
                // 保存选中位置
                currentRowOffset = 0;
                currentRowIndex = 0;
                firstRowIndex = 0;
                if (this.SelectedRows.Count > 0)
                {
                    firstRowIndex = this.FirstDisplayedScrollingRowIndex;
                    currentRowIndex = this.SelectedRows[0].Index;
                    currentRowOffset = currentRowIndex - this.FirstDisplayedScrollingRowIndex;
                }
                currentColumnOffset = this.FirstDisplayedScrollingColumnIndex;

                base.DataSource = value;

                // 恢复选中位置
                if (currentRowIndex <= this.Rows.Count - 1)
                {
                    this.FirstDisplayedScrollingRowIndex = firstRowIndex;
                    this.CurrentCell = this.Rows[currentRowIndex].Cells[0];
                }
                else
                {
                    int selectedRowIndex = Math.Min(Math.Min(currentRowOffset, this.Rows.Count - 1), this.DisplayedRowCount(false) - 1);
                    if (selectedRowIndex < this.Rows.Count && selectedRowIndex >= 0)
                    {
                        this.CurrentCell = this.Rows[selectedRowIndex].Cells[0];
                    }
                }
                if (currentColumnOffset > frozeColumns)
                {
                    this.FirstDisplayedScrollingColumnIndex = currentColumnOffset;
                }
            }
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            int i = 0, show = 0;

            switch (keyData)
            {
                case Keys.Left:
                    i = this.FirstDisplayedScrollingColumnIndex;
                    i--;
                    while (!this.Columns[i].Visible)
                        i--;
                    if (i >= frozeColumns)
                    {
                        this.FirstDisplayedScrollingColumnIndex = i;
                    }
                    return true;

                case Keys.Right:
                    i = this.FirstDisplayedScrollingColumnIndex;
                    i++;
                    while (!this.Columns[i].Visible)
                        i++;

                    show = 0;
                    for (int j = i; j < this.Columns.Count; j++)
                    {
                        if (this.Columns[j].Visible)
                            show++;
                    }

                    if (this.DisplayedColumnCount(true) < show + frozeColumns)
                    {
                        this.FirstDisplayedScrollingColumnIndex = i;
                    }
                    return true;

                case Keys.Tab:
                    i = 0;
                    show = 0;
                    for (int j = 0; j < this.Columns.Count; j++)
                    {
                        if (this.Columns[j].Visible)
                        {
                            show++;
                            if (show >= 15)
                            {
                                i = j;
                                break;
                            }
                        }
                    }

                    /*show = 0;
                    for (int j = this.FirstDisplayedScrollingColumnIndex; j < this.Columns.Count; j++)
                    {
                        if (this.Columns[j].Visible)
                        {
                            show++;
                        }
                    }
                    bool end = (show + 1 < this.DisplayedColumnCount(true));*/
                    if (this.FirstDisplayedScrollingColumnIndex >= i)
                        SendKeys.Send("{HOME}");
                    else
                        this.FirstDisplayedScrollingColumnIndex = i;
                    return true;

                /*case Keys.Home:
                    i = 0;
                    for (int j = frozeColumns; j < this.Columns.Count; j++)
                    {
                        if (this.Columns[j].Visible)
                        {
                            i = j;
                            break;
                        }
                    }
                    this.FirstDisplayedScrollingColumnIndex = i;
                    return true;

                case Keys.End:
                    SendKeys.Send(string.Format("{{RIGHT {0}}}", this.Columns.Count - frozeColumns));
                    return true;*/

                case Keys.Home:
                    if (this.Rows.Count > 0)
                    {
                        this.FirstDisplayedScrollingRowIndex = 0;
                        this.CurrentCell = this.Rows[0].Cells[0];
                    }
                    return true;

                case Keys.End:
                    if (this.Rows.Count > 0)
                    {
                        int displayRowCount = this.DisplayedRowCount(false);
                        this.FirstDisplayedScrollingRowIndex = (this.Rows.Count - 1 - displayRowCount) >= 0 ? (this.Rows.Count - 1 - displayRowCount) : 0;
                        this.CurrentCell = this.Rows[this.Rows.Count - 1].Cells[0];
                    }
                    return true;

                case Keys.PageUp:
                    ScrollPage(1);
                    return true;

                case Keys.PageDown:
                    ScrollPage(-1);
                    return true;
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void StockGridControl_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            e.PaintBackground(e.CellBounds, true);
            e.PaintContent(e.CellBounds);
            e.Handled = true;
        }

        private void StockGridControl_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            DataGridViewCell cell = Rows[e.RowIndex].Cells[e.ColumnIndex];
            float close = Convert.ToSingle(cell.OwningRow.Cells["Close"].Value);
            float nw = Convert.ToSingle(cell.OwningRow.Cells["New"].Value);

            switch (cell.OwningColumn.Name)
            {
                case "No":
                    e.Value = e.RowIndex + 1;
                    break;

                case "Open":    //今开
                    float open = Convert.ToSingle(cell.OwningRow.Cells["Open"].Value);
                    ChangeCellStyle(e, open - close, open <= 0);
                    break;

                case "High":    //最高
                    float high = Convert.ToSingle(cell.OwningRow.Cells["High"].Value);
                    ChangeCellStyle(e, high - close, high <= 0);
                    break;

                case "Low":     //最低
                    float low = Convert.ToSingle(cell.OwningRow.Cells["Low"].Value);
                    ChangeCellStyle(e, low - close, low <= 0);
                    break;

                case "New":     //最新
                    ChangeCellStyle(e, nw - close, nw <= 0);
                    break;

                case "Amplitude":   //涨幅
                    if (close != 0)
                    {
                        e.Value = (nw - close) * 100 / close;
                    }
                    ChangeCellStyle(e, nw - close, close <= 0 || nw <= 0);
                    break;

                case "Diff":     //涨跌
                    float diff = Convert.ToSingle(cell.OwningRow.Cells["Diff"].Value);
                    ChangeCellStyle(e, diff, false);
                    break;

                case "BuySellRatio":     //委比
                    float buySellRatio = Convert.ToSingle(cell.OwningRow.Cells["BuySellRatio"].Value);
                    ChangeCellStyle(e, buySellRatio, nw <= 0);
                    break;

                case "BuySellDiff":     //委差
                    float buySellDiff = Convert.ToSingle(cell.OwningRow.Cells["BuySellRatio"].Value);
                    ChangeCellStyle(e, buySellDiff, nw <= 0);
                    break;
            }

            if (Rows[e.RowIndex].Selected)
            {
                e.CellStyle.SelectionForeColor = e.CellStyle.ForeColor;
            }
        }

        private void StockGridControl_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && e.RowIndex >= 0 && e.ColumnIndex >= 0)
            {
                this.CurrentCell = this.Rows[e.RowIndex].Cells[e.ColumnIndex];
            }
        }

        private void StockGridControl_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
        {
            if (Rows[e.RowIndex].Selected)
            {
                e.Graphics.DrawLine(Pens.LightCyan, e.RowBounds.Left + 0, e.RowBounds.Bottom - 1, e.RowBounds.Right - 0, e.RowBounds.Bottom - 1);
            }
        }

        private void StockGridControl_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left || e.Clicks != 1)
                return;

            //获取栏位
            if (e.ColumnIndex < 0 || this.Columns[e.ColumnIndex].HeaderCell == null)
                return;

            DataGridViewColumn column = this.Columns[e.ColumnIndex];
            if (column.SortMode == DataGridViewColumnSortMode.NotSortable)
                return;

            if (column == SortNeededColumn)
            {
                SortNeededOrder = (SortNeededOrder == SortOrder.Descending) ? SortOrder.Ascending : SortOrder.Descending;
            }
            SortNeededColumn = column;

            if (SortNeeded != null)
            {
                SortNeeded(this, new EventArgs());
            }
        }

        private void ChangeCellStyle(DataGridViewCellFormattingEventArgs e, float diff, bool change)
        {
            if (change)
            {
                e.Value = "─";
                e.CellStyle.ForeColor = StockProfile.Colors.GridTextColor;

            }
            else
            {
                if (diff > 0)
                    e.CellStyle.ForeColor = StockProfile.Colors.UpTextColor;
                else if (diff < 0)
                    e.CellStyle.ForeColor = StockProfile.Colors.DnTextColor;
                else
                    e.CellStyle.ForeColor = StockProfile.Colors.GridTextColor;
            }
        }

        private void ScrollPage(int pageNumber)
        {
            int numberOfLinesToMove = pageNumber * this.DisplayedRowCount(false);

            if (numberOfLinesToMove > 0)
            {
                if (this.FirstDisplayedScrollingRowIndex > numberOfLinesToMove)
                {
                    this.FirstDisplayedScrollingRowIndex -= numberOfLinesToMove;
                }
                else
                {
                    this.FirstDisplayedScrollingRowIndex = 0;
                }
                this.CurrentCell = this.Rows[this.FirstDisplayedScrollingRowIndex].Cells[0];

            }
            else if (numberOfLinesToMove < 0)
            {
                numberOfLinesToMove *= -1;
                if (this.FirstDisplayedScrollingRowIndex + numberOfLinesToMove < this.Rows.Count)
                {
                    this.FirstDisplayedScrollingRowIndex += numberOfLinesToMove;
                    this.CurrentCell = this.Rows[this.FirstDisplayedScrollingRowIndex].Cells[0];
                }
                else
                {
                    this.CurrentCell = this.Rows[this.Rows.Count - 1].Cells[0];
                }


                /*int rowCount = this.DisplayedRowCount(false);
                if (this.FirstDisplayedScrollingRowIndex + rowCount - 1 < this.Rows.Count)
                    this.CurrentCell = this.Rows[this.FirstDisplayedScrollingRowIndex + rowCount - 1].Cells[0];
                else
                    this.CurrentCell = this.Rows[this.Rows.Count - 1].Cells[0];*/
            }
        }
    }
}
